package jsonutil

import (
	"bytes"
	"encoding/json"
	"os"
	"reflect"
	"strings"

	"gitee.com/tomatomeatman/golang-repository/bricks/model/emity"
	Log "github.com/cihub/seelog"
)

type JsonUtil struct{}

// json字符串转map
func (ju JsonUtil) JsonToMap(jsonStr string) (map[string]string, error) {
	if "" == jsonStr {
		return make(map[string]string), nil
	}

	m := make(map[string]string)
	err := json.Unmarshal([]byte(jsonStr), &m)
	if err != nil {
		Log.Error("Json字符串转换异常: %+v\n", err)
		return nil, err
	}

	return m, nil
}

// json字符串转map
func (ju JsonUtil) ToMap(jsonStr string) (map[string]interface{}, error) {
	if "" == jsonStr {
		return make(map[string]interface{}), nil
	}

	m := make(map[string]interface{})
	err := json.Unmarshal([]byte(jsonStr), &m)
	if err != nil {
		Log.Error("Json字符串转换异常: %+v\n", err)
		return nil, err
	}

	return m, nil
}

// 文件转map
func (ju JsonUtil) MapFromFile(path string) (map[string]interface{}, error) {
	_, err := os.Stat(path) //os.Stat获取文件信息
	if err != nil {
		if !os.IsExist(err) {
			return nil, err
		}
	}

	data, err := os.ReadFile(path)
	if err != nil {
		return nil, err
	}

	m := make(map[string]interface{})
	err = json.Unmarshal(data, &m)
	if err != nil {
		Log.Error("Json字符串转换异常: %+v\n", err)
		return nil, err
	}

	return m, nil
}

// 文件转JsonArray
func (ju JsonUtil) ArrayFromFile(path string) ([]map[string]interface{}, error) {
	_, err := os.Stat(path) //os.Stat获取文件信息
	if err != nil {
		if !os.IsExist(err) {
			return nil, err
		}
	}

	data, err := os.ReadFile(path)
	if err != nil {
		return nil, err
	}

	m := []map[string]interface{}{}
	err = json.Unmarshal(data, &m)
	if err != nil {
		Log.Error("Json字符串转换异常: %+v\n", err)
		return nil, err
	}

	return m, nil
}

// 转换json到文件
func (ju JsonUtil) ToFile(data interface{}, path string) bool {
	if nil == data {
		return false
	}

	iEd := strings.LastIndex(path, "/")
	dir := path[:iEd]
	if "." != dir {
		os.MkdirAll(dir, os.ModePerm)
	}

	//byteData, _ := json.Marshal(data)//直接使用json.Marshal存在转义问题,例如'&变成\u0026'

	buffer := &bytes.Buffer{}
	encoder := json.NewEncoder(buffer)
	encoder.SetEscapeHTML(false)

	err := encoder.Encode(data)
	if err != nil {
		Log.Error("转换数据发生异常:", err)
		return false
	}

	err = os.WriteFile(path, buffer.Bytes(), 0666) // 保存到文件
	if err != nil {
		Log.Error("保存文件发生异常:", err)
		return false
	}

	return true
}

// 文件转换到结构
func (ju JsonUtil) FormFile(path string, entity interface{}) *emity.MsgEmity {
	if nil == entity {
		entity = map[string]interface{}{}
	}

	if !ju.isExist(path) {
		return emity.MsgEmity{}.Err(1001, "文件不存在")
	}

	data, err := os.ReadFile(path)
	if err != nil {
		return emity.MsgEmity{}.Err(1002, "读取失败")
	}

	if len(data) < 1 {
		return emity.MsgEmity{}.Err(1003, "没有数据")
	}

	rt := reflect.TypeOf(entity)
	result := reflect.New(rt).Elem().Interface()

	err = json.Unmarshal(data, &result)
	if err != nil {
		Log.Error("Json字符串转换异常: %+v\n", err)
		return emity.MsgEmity{}.Err(1004, "字符串转换异常")
	}

	resultTypeName := reflect.TypeOf(result).String()
	if resultTypeName == rt.String() {
		return emity.MsgEmity{}.Success(result, "转换结束,格式相符")
	}

	entityTypeName := rt.String()
	if strings.HasPrefix(entityTypeName, "map[string]interface") {
		return emity.MsgEmity{}.Success(result, "转换结束,格式相符")
	}

	if strings.HasPrefix(resultTypeName, "[]interface") && strings.Contains("/[]string/[]int/[]int64/", entityTypeName) {
		switch entityTypeName {
		case "[]string":
			l := len(result.([]interface{}))
			newResult := make([]string, l)
			for i := 0; i < l; i++ {
				newResult = append(newResult, (result.([]interface{}))[i].(string))
			}

			return emity.MsgEmity{}.Success(newResult, "转换结束,返回类型'[]string'")
		case "[]int":
			l := len(result.([]interface{}))
			newResult := make([]int, l)
			for i := 0; i < l; i++ {
				newResult = append(newResult, (result.([]interface{}))[i].(int))
			}

			return emity.MsgEmity{}.Success(newResult, "转换结束,返回类型'[]int'")
		case "[]int64":
			l := len(result.([]interface{}))
			newResult := make([]int64, l)
			for i := 0; i < l; i++ {
				newResult = append(newResult, (result.([]interface{}))[i].(int64))
			}

			return emity.MsgEmity{}.Success(newResult, "转换结束,返回类型'[]int64'")
		}

		return emity.MsgEmity{}.Success(result, "转换结束,返回类型'[]interface{}'")
		// sliceType := reflect.SliceOf(rt)
		// valueSlice := reflect.MakeSlice(sliceType, 0, 0)

		// for _, val := range result.([]interface{}) {
		// 	valueSlice = reflect.Append(valueSlice, reflect.ValueOf(val))
		// }

		// return emity.MsgEmity{}.Success(valueSlice.Interface(), "转换结束")
	}

	if strings.HasPrefix(resultTypeName, "[]") {
		sliceType := reflect.SliceOf(rt)
		// sliceValue := reflect.New(sliceType).Elem()
		// fmt.Println(sliceValue.String())

		valueSlice := reflect.MakeSlice(sliceType, 0, 0)

		l := len(result.([]interface{}))
		for i := 0; i < l; i++ {
			var val map[string]interface{}
			val = (result.([]interface{}))[i].(map[string]interface{})

			obj := reflect.New(rt).Elem()
			for k, v := range val {
				field := obj.FieldByName(k)
				if field.IsValid() {
					field.Set(reflect.ValueOf(v))
					continue
				}

				field = obj.FieldByName("G" + k)
				if field.IsValid() {
					field.Set(reflect.ValueOf(v))
				}
			}

			valueSlice = reflect.Append(valueSlice, obj)
		}

		return emity.MsgEmity{}.Success(valueSlice.Interface(), "转换结束")
	}

	if !strings.HasPrefix(resultTypeName, "map[string]interface") {
		return emity.MsgEmity{}.Success(result, "转换结束")
	}

	// if !strings.HasPrefix(resultTypeName, "map[string]") {
	// 	kType := reflect.TypeOf("")
	// 	mapType := reflect.MapOf(kType, rt)
	// 	valueMap := reflect.MakeMap(mapType)

	// 	for key, val := range result.(map[string]map[string]interface{}) {
	// 		obj := reflect.New(rt).Elem()
	// 		for k, v := range val {
	// 			field := obj.FieldByName(k)
	// 			if field.IsValid() {
	// 				field.Set(reflect.ValueOf(v))
	// 				continue
	// 			}

	// 			field = obj.FieldByName("G" + k)
	// 			if field.IsValid() {
	// 				field.Set(reflect.ValueOf(v))
	// 			}
	// 		}

	// 		valueMap.SetMapIndex(reflect.ValueOf(key), obj)
	// 	}

	// 	return emity.MsgEmity{}.Success(valueMap.Interface(), "转换结束")
	// }

	//--如果转换发生错误则进行再次转换--//
	var vMap map[string]interface{}
	vMap = result.(map[string]interface{})
	rve := reflect.New(reflect.TypeOf(entity)).Elem()
	for key, val := range vMap {
		field := rve.FieldByName(key)
		if !field.IsValid() {
			continue
		}

		if (field.Type().String() == "int64") && (reflect.TypeOf(val).String() == "float64") {
			field.Set(reflect.ValueOf(int64(val.(float64))))
			continue
		}

		field.Set(reflect.ValueOf(val))
	}

	return emity.MsgEmity{}.Success(rve.Interface(), "转换结束")
}

/**
 * 对象转换到字符串
 * 直接使用json.Marshal存在转义问题,例如'&变成\u0026'
 */
func (ju JsonUtil) ToStr(data interface{}) string {
	if nil == data {
		return ""
	}

	buffer := &bytes.Buffer{}
	encoder := json.NewEncoder(buffer)
	encoder.SetEscapeHTML(false)

	err := encoder.Encode(data)
	if err != nil {
		return ""
	}

	return string(buffer.Bytes())
}

// 内容转换到结构实体
func (ju JsonUtil) ToObj(str string, entity interface{}) *emity.MsgEmity {
	if nil == entity {
		entity = map[string]interface{}{}
	}

	str = strings.TrimSpace(str)
	if str == "" {
		return emity.MsgEmity{}.Err(1003, "没有数据")
	}

	rve := reflect.New(reflect.TypeOf(entity)).Elem()
	result := rve.Interface()

	err := json.Unmarshal([]byte(str), &result)
	if err != nil {
		Log.Error("Json字符串转换异常: %+v\n", err)
		return emity.MsgEmity{}.Err(1004, "字符串转换异常")
	}

	if (!strings.Contains(reflect.TypeOf(result).String(), "map[string]interface")) && (!strings.Contains(reflect.TypeOf(entity).String(), "map[string]interface")) {
		return emity.MsgEmity{}.Success(result, "转换结束")
	}

	//--如果转换发生错误则进行再次转换--//
	var vMap map[string]interface{}
	vMap = result.(map[string]interface{})
	for key, val := range vMap {
		field := rve.FieldByName(key)
		if !field.IsValid() {
			continue
		}

		if (field.Type().String() == "int64") && (reflect.TypeOf(val).String() == "float64") {
			field.Set(reflect.ValueOf(int64(val.(float64))))
			continue
		}

		field.Set(reflect.ValueOf(val))
	}

	return emity.MsgEmity{}.Success(rve.Interface(), "转换结束")
}

// 判断所给路径文件/文件夹是否存在(返回true是存在)
func (ju JsonUtil) isExist(path string) bool {
	_, err := os.Stat(path) //os.Stat获取文件信息
	if err != nil {
		if os.IsExist(err) {
			return true
		}
		return false
	}

	return true
}
